<!DOCTYPE html> <!-- -*- html -*- -->
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1">
  <title>Similar matrices</title>
  <link rel="shortcut icon" href="img/gatech.gif"/>

  
      <link rel="stylesheet" href="css/demo.css?vers=2759ff">
  

  <style>
      

html, body {
    margin:           0;
    height:           100%;
    background-color: white;
    overflow-x:       hidden;
}
.mathbox-wrapper {
    width:       50%;
    padding-top: 50%;
    position:    absolute;
    left:        0;
    top:         50%;
    transform:   translate(0, -50%);
}
.mathbox-wrapper + .mathbox-wrapper {
    left:        50%;
}
.mathbox-wrapper > div {
    position: absolute;
    top:      0;
    left:     0;
    width:    100%;
    height:   100%;
}
.mathbox-label {
    position:  absolute;
    left:      50%;
    top:       10px;
    color:     black;
    opacity:   1.0;
    background-color: rgba(220, 220, 220, .5);
    border:    solid 1px rgba(50, 50, 50, .5);
    padding:   5px;
    transform: translate(-50%, 0);
}
.overlay-text {
    z-index: 1;
}

#captions3 {
  position:    absolute;
  left:        50%;
  top:         initial;
  transform:   translate(-50%, 0);
  bottom:      10px;
  z-index:     2;
}

  </style>

</head>
<body>
    
<div id="captions3" class="overlay-text">
<p>
    <span id="mat-here3"></span><br>
    <span id="sim-here"></span><br>
</p>
</div>


<div class="mathbox-wrapper">
    <div id="mathbox1">
        
<div id="captions1" class="overlay-text">
<p><span id="mat-here1"></span><span id="mult-here1"></span></p>
</div>

    </div>
</div>
<div class="mathbox-wrapper">
    <div id="mathbox2">
        
<div id="captions2" class="overlay-text">
<p><span id="mat-here2"></span><span id="mult-here2"></span></p>
</div>

    </div>
</div>



    
        <script src="js/demo.js?vers=77646a"></script>
    

    <script type="text/javascript">
        "use strict";
        DomReady.ready(function() {

        var A, AName, B, BName, C, CName, Ce1, Ce2, Ce3, Cinv, aXColor, axis1Color, axis2Color, axis3Color, bColor, bxBColor, colors, computeOut, e1, e2, e3, gui, is3d, labels, mult33, params, ref, ref1, ref2, size, snap, tB, tB4, tB4inv, tBinv, tC, tC4, tCinv, transpose, updateCaption, vectorIn1, vectorIn2, vectorOut1, vectorOut2, xColor;

vectorIn1 = urlParams.get('x', 'float[]', [-1, 1, 3]);

vectorOut1 = [0, 0, 0];

vectorIn2 = [-1, 1, 3];

vectorOut2 = [0, 0, 0];

labels = urlParams.get('labels', 'str[]', ['v1', 'v2', 'v3']);

AName = (ref = urlParams.AName) != null ? ref : 'A';

BName = (ref1 = urlParams.BName) != null ? ref1 : 'B';

CName = (ref2 = urlParams.CName) != null ? ref2 : 'C';

B = urlParams.get('B', 'matrix', [[2, 0], [0, 3]]);

C = urlParams.get('C', 'matrix', [[2, 1], [1, 1]]);

size = B.length;

if (size === 2) {
  vectorIn1[2] = 0;
  vectorIn2[2] = 0;
}

is3d = size === 3;

transpose = function(mat) {
  var i, j, k, l, ref3, ref4, tmp;
  tmp = [];
  for (i = k = 0; k < 3; i = ++k) {
    tmp[i] = [];
    for (j = l = 0; l < 3; j = ++l) {
      tmp[i][j] = (ref3 = (ref4 = mat[j]) != null ? ref4[i] : void 0) != null ? ref3 : 0;
    }
  }
  if (size === 2) {
    tmp[2][2] = 1;
  }
  return tmp;
};

B = transpose(B);

C = transpose(C);

tB = new THREE.Matrix3();

tB.set(B[0][0], B[1][0], B[2][0], B[0][1], B[1][1], B[2][1], B[0][2], B[1][2], B[2][2]);

tB4 = new THREE.Matrix4();

tB4.set(B[0][0], B[1][0], B[2][0], 0, B[0][1], B[1][1], B[2][1], 0, B[0][2], B[1][2], B[2][2], 0, 0, 0, 0, 1);

tB4inv = new THREE.Matrix4().getInverse(tB4);

tBinv = new THREE.Matrix3().getInverse(tB4);

tC = new THREE.Matrix3();

tC.set(C[0][0], C[1][0], C[2][0], C[0][1], C[1][1], C[2][1], C[0][2], C[1][2], C[2][2]);

tC4 = new THREE.Matrix4();

tC4.set(C[0][0], C[1][0], C[2][0], 0, C[0][1], C[1][1], C[2][1], 0, C[0][2], C[1][2], C[2][2], 0, 0, 0, 0, 1);

tCinv = new THREE.Matrix3().getInverse(tC4);

Cinv = tCinv.toArray();

Cinv = [[Cinv[0], Cinv[1], Cinv[2]], [Cinv[3], Cinv[4], Cinv[5]], [Cinv[6], Cinv[7], Cinv[8]]];

mult33 = function(mat1, mat2) {
  var out;
  out = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
  out[0][0] = mat1[0][0] * mat2[0][0] + mat1[1][0] * mat2[0][1] + mat1[2][0] * mat2[0][2];
  out[1][0] = mat1[0][0] * mat2[1][0] + mat1[1][0] * mat2[1][1] + mat1[2][0] * mat2[1][2];
  out[2][0] = mat1[0][0] * mat2[2][0] + mat1[1][0] * mat2[2][1] + mat1[2][0] * mat2[2][2];
  out[0][1] = mat1[0][1] * mat2[0][0] + mat1[1][1] * mat2[0][1] + mat1[2][1] * mat2[0][2];
  out[1][1] = mat1[0][1] * mat2[1][0] + mat1[1][1] * mat2[1][1] + mat1[2][1] * mat2[1][2];
  out[2][1] = mat1[0][1] * mat2[2][0] + mat1[1][1] * mat2[2][1] + mat1[2][1] * mat2[2][2];
  out[0][2] = mat1[0][2] * mat2[0][0] + mat1[1][2] * mat2[0][1] + mat1[2][2] * mat2[0][2];
  out[1][2] = mat1[0][2] * mat2[1][0] + mat1[1][2] * mat2[1][1] + mat1[2][2] * mat2[1][2];
  out[2][2] = mat1[0][2] * mat2[2][0] + mat1[1][2] * mat2[2][1] + mat1[2][2] * mat2[2][2];
  return out;
};

A = mult33(mult33(C, B), Cinv);

e1 = [1, 0, 0];

e2 = [0, 1, 0];

e3 = [0, 0, 1];

Ce1 = C[0];

Ce2 = C[1];

Ce3 = C[2];

bColor = new Color("yellow");

bxBColor = bColor.darken(.2);

xColor = new Color("violet");

aXColor = xColor.darken(.2);

axis1Color = new Color("red");

axis2Color = new Color("blue");

axis3Color = new Color("green");

colors = [bColor.arr(1), bxBColor.arr(.7), axis1Color.arr(.8), axis2Color.arr(.8), axis3Color.arr(.8)].slice(0, size + 2);

updateCaption = null;

computeOut = null;

gui = null;

snap = false;

params = {};

if (urlParams.snap !== 'disabled') {
  gui = true;
  params["Snap axes"] = urlParams.snap !== 'off';
  gui = new dat.GUI;
  gui.closed = urlParams.closed != null;
  gui.add(params, "Snap axes").onFinishChange(function(val) {
    return snap = val;
  });
  snap = params["Snap axes"];
}

window.demo1 = new (size === 3 ? Demo : Demo2D)({
  mathbox: {
    element: document.getElementById("mathbox1")
  }
}, function() {
  var clipCube, diff, elt, eq1Elt, eq2Elt, labeled, mat1Elt, mat2Elt, mat3Elt, onDrag, r, snapThreshold, snapped, subspace1, subspace2, subspace3, subspaces, tmpVec, view;
  window.mathbox1 = this.mathbox;
  this.range = this.urlParams.get('range1', 'float', 5);
  r = this.range;
  view = this.view({
    name: 'view1',
    viewRange: [[-r, r], [-r, r], [-r, r]].slice(0, size),
    axes: false,
    grid: false
  });
  labeled = this.labeledVectors(view, {
    vectors: [vectorIn1, vectorOut1, e1, e2, e3].slice(0, size + 2),
    colors: colors,
    labels: ['[x]_B', BName + '[x]_B', 'e1', 'e2', 'e3'].slice(0, size + 2),
    live: true,
    zeroPoints: true,
    zeroThreshold: 0.3,
    vectorOpts: {
      zIndex: 2
    },
    labelOpts: {
      zIndex: 3,
      outline: 1,
      background: "white"
    },
    zeroOpts: {
      zIndex: 3
    }
  });
  clipCube = this.clipCube(view, {
    draw: true,
    hilite: size === 3
  });
  clipCube.clipped.area({
    width: 11,
    height: 11,
    channels: size,
    rangeX: [-r, r],
    rangeY: [-r, r]
  }).surface({
    color: [0.5, 0.5, 0.5, 0.5],
    opacity: 0.5,
    lineX: true,
    lineY: true,
    fill: false,
    zBias: 0
  }).array({
    channels: 4,
    width: 2,
    items: size,
    data: [[colors[2], colors[3], colors[4]].slice(0, size), [colors[2], colors[3], colors[4]].slice(0, size)]
  }).array({
    width: 2,
    items: size,
    channels: size,
    data: size === 2 ? [[-r, 0], [0, -r], [r, 0], [0, r]] : [[-r, 0, 0], [0, -r, 0], [0, 0, -r], [r, 0, 0], [0, r, 0], [0, 0, r]]
  }).line({
    color: "white",
    colors: "<<",
    width: 2,
    opacity: 1,
    zBias: 1
  });
  tmpVec = new THREE.Vector3();
  computeOut = (function(_this) {
    return function() {
      tmpVec.set.apply(tmpVec, vectorIn1).applyMatrix3(tB);
      vectorOut1[0] = tmpVec.x;
      vectorOut1[1] = tmpVec.y;
      vectorOut1[2] = tmpVec.z;
      tmpVec.applyMatrix3(tC);
      vectorOut2[0] = tmpVec.x;
      vectorOut2[1] = tmpVec.y;
      vectorOut2[2] = tmpVec.z;
      tmpVec.set.apply(tmpVec, vectorIn1).applyMatrix3(tC);
      vectorIn2[0] = tmpVec.x;
      vectorIn2[1] = tmpVec.y;
      vectorIn2[2] = tmpVec.z;
      return updateCaption();
    };
  })(this);
  snapThreshold = 1.0 * this.range / 10.0;
  snapped = new THREE.Vector3();
  diff = new THREE.Vector3();
  subspace1 = this.subspace({
    vectors: [e1]
  });
  subspace2 = this.subspace({
    vectors: [e2]
  });
  subspace3 = this.subspace({
    vectors: [e3]
  });
  subspaces = [subspace1, subspace2, subspace3];
  onDrag = (function(_this) {
    return function(vec) {
      var k, len, results, subspace;
      if (!snap) {
        return;
      }
      results = [];
      for (k = 0, len = subspaces.length; k < len; k++) {
        subspace = subspaces[k];
        subspace.project(vec, snapped);
        diff.copy(vec).sub(snapped);
        if (diff.lengthSq() <= snapThreshold) {
          results.push(vec.copy(snapped));
        } else {
          results.push(void 0);
        }
      }
      return results;
    };
  })(this);
  this.drag = this.draggable(view, {
    points: [vectorIn1],
    onDrag: onDrag,
    postDrag: computeOut
  });
  mat1Elt = document.getElementById('mat-here1');
  mat2Elt = document.getElementById('mat-here2');
  mat3Elt = document.getElementById('mat-here3');
  katex.render((BName + " = ") + this.texMatrix(B, {
    rows: size,
    cols: size
  }), mat1Elt);
  katex.render((AName + " = ") + this.texMatrix(A, {
    rows: size,
    cols: size
  }), mat2Elt);
  katex.render((CName + " = ") + this.texMatrix(C, {
    rows: size,
    cols: size
  }), mat3Elt);
  elt = document.getElementById("sim-here");
  katex.render((AName + " = " + CName + BName + CName + "^{-1} ") + ("\\quad \\color{" + (xColor.str()) + "}{x} = ") + (CName + "\\color{" + (bColor.str()) + "}{[x]_{\\mathcal B}}"), elt);
  eq1Elt = document.getElementById('mult-here1');
  eq2Elt = document.getElementById('mult-here2');
  return updateCaption = (function(_this) {
    return function() {
      var str;
      str = "\\qquad " + BName;
      str += _this.texVector(vectorIn1, {
        dim: size,
        color: bColor
      });
      str += '=';
      str += _this.texVector(vectorOut1, {
        dim: size,
        color: bxBColor
      });
      katex.render(str, eq1Elt);
      str = "\\qquad " + AName;
      str += _this.texVector(vectorIn2, {
        dim: size,
        color: xColor
      });
      str += '=';
      str += _this.texVector(vectorOut2, {
        dim: size,
        color: aXColor
      });
      return katex.render(str, eq2Elt);
    };
  })(this);
});

window.demo2 = new (size === 3 ? Demo : Demo2D)({
  mathbox: {
    element: document.getElementById("mathbox2")
  }
}, function() {
  var clipCube, colors2, computeIn, diff, labeled, onDrag, r, r2, snapThreshold, snapped, subspace1, subspace2, subspace3, subspaces, tmpVec, view;
  window.mathbox2 = this.mathbox;
  this.range = this.urlParams.get('range2', 'float', 5);
  r = this.range;
  view = this.view({
    name: 'view2',
    viewRange: [[-r, r], [-r, r], [-r, r]].slice(0, size),
    axes: false,
    grid: false
  });
  colors2 = colors.slice();
  colors2[0] = xColor.arr(1);
  colors2[1] = aXColor.arr(.7);
  labeled = this.labeledVectors(view, {
    vectors: [vectorIn2, vectorOut2, Ce1, Ce2, Ce3].slice(0, size + 2),
    colors: colors2,
    labels: ['x', AName + 'x'].concat(labels).slice(0, size + 2),
    live: true,
    zeroPoints: true,
    zeroThreshold: 0.3,
    vectorOpts: {
      zIndex: 2
    },
    labelOpts: {
      zIndex: 3,
      outline: 1,
      background: "white"
    },
    zeroOpts: {
      zIndex: 3
    }
  });
  clipCube = this.clipCube(view, {
    draw: true,
    hilite: size === 3
  });
  this.transformed = clipCube.clipped.transform({
    matrix: [C[0][0], C[1][0], C[2][0], 0, C[0][1], C[1][1], C[2][1], 0, C[0][2], C[1][2], C[2][2], 0, 0, 0, 0, 1]
  });
  r2 = demo1.range * 5;
  this.transformed.area({
    width: 51,
    height: 51,
    channels: size,
    rangeX: [-r2, r2],
    rangeY: [-r2, r2]
  }).surface({
    color: [0.5, 0.5, 0.5, 0.5],
    opacity: 0.5,
    lineX: true,
    lineY: true,
    fill: false,
    zBias: 0
  }).array({
    channels: 4,
    width: 2,
    items: size,
    data: [[colors[2], colors[3], colors[4]].slice(0, size), [colors[2], colors[3], colors[4]].slice(0, size)]
  }).array({
    width: 2,
    items: size,
    channels: size,
    data: size === 2 ? [[-r2, 0], [0, -r2], [r2, 0], [0, r2]] : [[-r2, 0, 0], [0, -r2, 0], [0, 0, -r2], [r2, 0, 0], [0, r2, 0], [0, 0, r2]]
  }).line({
    color: "white",
    colors: "<<",
    width: 2,
    opacity: 1,
    zBias: 1
  });
  tmpVec = new THREE.Vector3();
  computeIn = function() {
    tmpVec.set.apply(tmpVec, vectorIn2).applyMatrix3(tCinv);
    vectorIn1[0] = tmpVec.x;
    vectorIn1[1] = tmpVec.y;
    vectorIn1[2] = tmpVec.z;
    tmpVec.applyMatrix3(tB);
    vectorOut1[0] = tmpVec.x;
    vectorOut1[1] = tmpVec.y;
    vectorOut1[2] = tmpVec.z;
    tmpVec.applyMatrix3(tC);
    vectorOut2[0] = tmpVec.x;
    vectorOut2[1] = tmpVec.y;
    vectorOut2[2] = tmpVec.z;
    return updateCaption();
  };
  snapThreshold = 1.0 * this.range / 10.0;
  snapped = new THREE.Vector3();
  diff = new THREE.Vector3();
  subspace1 = this.subspace({
    vectors: [Ce1]
  });
  subspace2 = this.subspace({
    vectors: [Ce2]
  });
  subspace3 = this.subspace({
    vectors: [Ce3]
  });
  subspaces = [subspace1, subspace2, subspace3];
  onDrag = (function(_this) {
    return function(vec) {
      var k, len, results, subspace;
      if (!snap) {
        return;
      }
      results = [];
      for (k = 0, len = subspaces.length; k < len; k++) {
        subspace = subspaces[k];
        subspace.project(vec, snapped);
        diff.copy(vec).sub(snapped);
        if (diff.lengthSq() <= snapThreshold) {
          results.push(vec.copy(snapped));
        } else {
          results.push(void 0);
        }
      }
      return results;
    };
  })(this);
  return this.drag = this.draggable(view, {
    points: [vectorIn2],
    onDrag: onDrag,
    postDrag: computeIn
  });
});

groupControls(demo1, demo2);

computeOut();


        });
    </script>
</body>
</html>

